﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NodeSource.Executor
{
    public enum Operator
    {
        Add,
        Subtract,
        Multiply,
        Divide,
        GreaterThan,
        LessThan,
        GreaterThanOrEqualTo,
        LessThanOrEqualTo,
        EqualTo,
        PreIncrement,
        PostIncrement,
        Between,
        In
    }

    public class BinaryExpression : Expression
    {
        public readonly Expression LeftOperand;
        public readonly Expression RightOperand;
        public readonly Operator Operator;

        public BinaryExpression(Expression leftOperand, Expression rightOperand, Operator @operator)
        {
            LeftOperand = leftOperand;
            RightOperand = rightOperand;
            Operator = @operator;
        }
    }

    public class UnaryExpression : Expression
    {
        public readonly Expression Operand;
        public readonly Operator Operator;

        public UnaryExpression(Expression operand, Operator @operator)
        {
            Operand = operand;
            Operator = @operator;
        }
    }

    public class TernaryExpression : Expression
    {
        public readonly Expression LeftOperand;
        public readonly Expression MidOperand;
        public readonly Expression RightOperand;
        public readonly Operator Operator;

        public TernaryExpression(Expression leftOperand, Expression midOperand, Expression rightOperand, Operator @operator)
        {
            LeftOperand = leftOperand;
            MidOperand = midOperand;
            RightOperand = rightOperand;
            Operator = @operator;
        }
    }

    public class RangeExpression : Expression
    {

    }

    public class ConstantExpression : Expression
    {
        public readonly Object Value;
        public readonly FieldType FieldType;

        public ConstantExpression(object value, FieldType fieldType)
        {
            Value = value;
            FieldType = fieldType;
        }
    }

    public class ParameterExpression : Expression
    {
        public readonly String Name;

        public ParameterExpression(string name)
        {
            Name = name;
        }
    }

    public class Expression
    {
        public static ConstantExpression Constant(object value, FieldType fieldType)
        {
            return new ConstantExpression(value, fieldType);
        }

        public static ParameterExpression Parameter(String name)
        {
            return new ParameterExpression(name);
        }

        public static BinaryExpression Add(Expression leftOperand, Expression rightOperand)
        {
            return new BinaryExpression(leftOperand, rightOperand, Operator.Add);
        }

        public static BinaryExpression Subtract(Expression leftOperand, Expression rightOperand)
        {
            return new BinaryExpression(leftOperand, rightOperand, Operator.Subtract);
        }

        public static BinaryExpression Multiply(Expression leftOperand, Expression rightOperand)
        {
            return new BinaryExpression(leftOperand, rightOperand, Operator.Multiply);
        }

        public static BinaryExpression Divide(Expression leftOperand, Expression rightOperand)
        {
            return new BinaryExpression(leftOperand, rightOperand, Operator.Divide);
        }

        public static BinaryExpression GreaterThan(Expression leftOperand, Expression rightOperand)
        {
            return new BinaryExpression(leftOperand, rightOperand, Operator.GreaterThan);
        }

        public static BinaryExpression LessThan(Expression leftOperand, Expression rightOperand)
        {
            return new BinaryExpression(leftOperand, rightOperand, Operator.LessThan);
        }

        public static BinaryExpression EqualTo(Expression leftOperand, Expression rightOperand)
        {
            return new BinaryExpression(leftOperand, rightOperand, Operator.EqualTo);
        }

        public static TernaryExpression Between(Expression lessOperand, Expression comparisonOperand, Expression greaterOperand)
        {
            return new TernaryExpression(lessOperand, comparisonOperand, greaterOperand, Operator.Between);
        }

        public override string ToString()
        {
            if (this is ConstantExpression)
            {
                var expression = this as ConstantExpression;
                return expression.Value.ToString();
            }
            else if (this is ParameterExpression)
            {
                var expression = this as ParameterExpression;
                return String.Format("{0}", expression.Name);
            }
            else if (this is BinaryExpression)
            {
                var expression = this as BinaryExpression;
                var expr = "(" + expression.LeftOperand.ToString() + ")";
                switch (expression.Operator)
                {
                    case Operator.Add:
                        expr += " + ";
                        break;
                    case Operator.Subtract:
                        expr += " - ";
                        break;
                    case Operator.Multiply:
                        expr += " * ";
                        break;
                    case Operator.Divide:
                        expr += " / ";
                        break;
                    case Operator.GreaterThan:
                        expr += " > ";
                        break;
                    case Operator.LessThan:
                        expr += " < ";
                        break;
                    case Operator.GreaterThanOrEqualTo:
                        expr += " >= ";
                        break;
                    case Operator.LessThanOrEqualTo:
                        expr += " < ";
                        break;
                    case Operator.EqualTo:
                        expr += " = ";
                        break;
                }
                expr += "(" + expression.RightOperand.ToString() + ")";
                return expr;
            }

            throw new NotImplementedException();
        }
    }
}
